# coding = utf-8

import os
import sys
import win32api
import win32con
import win32gui
import ctypes
import time
import json
from urllib import request
import random
import winreg as reg

BING_URL = "https://s.cn.bing.net"
BASE_URL = "https://www.bing.com/HPImageArchive.aspx?format=js&n="
EXE_NAME = "BingImg.exe"
# 程序运行路径
EXE_PATH = os.path.abspath(os.path.dirname(sys.argv[0]))
# 图片保存地址
SAVE_PATH = os.path.join(EXE_PATH, "backgrounds")

IMG_EXT = ".jpg"
ICON_PATH = os.path.join(EXE_PATH, "logo.ico")
CURRENT_IMG = ""

# 链接重试
retryNum = 0
allowTryNum = 2
waitTime = 60

window_handle = None


# 下载图片
def save_bing_image(imgs, save_path):
    filePaths = []

    for img in imgs:
        try:
            # 设置图片文件名称
            baseName = str(img['enddate']) + IMG_EXT
            # 获得图片路径
            filePath = os.path.join(save_path, baseName)
            # 下载图片并保存
            request.urlretrieve(BING_URL + img['url'], filePath)

            filePaths.append(filePath)
        except IOError as e:
            print('图片保存错误：文件操作失败。', e, '\n')
        except Exception as e:
            print('图片保存错误：', e, '\n')
        else:
            print('图片保存成功：', filePath, '\n')

    return filePaths


# 设置指定图片屏保
def set_img_as_wallpaper(img_path):
    key = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER, "Control Panel\\Desktop", 0, win32con.KEY_SET_VALUE)
    win32api.RegSetValueEx(key, "WallpaperStyle", 0, win32con.REG_SZ, "2")
    win32api.RegSetValueEx(key, "TileWallpaper", 0, win32con.REG_SZ, "0")
    win32gui.SystemParametersInfo(win32con.SPI_SETDESKWALLPAPER, img_path, 1 + 2)
    print(img_path + ' 设置桌面壁纸成功')


# 设置随机图片为屏保
def set_day_img_as_wallpaper(folder_path, step):
    for root, directories, files in os.walk(os.path.join(folder_path, '')):
        backgrounds = [file.lower()
                       for file in files if file.endswith(IMG_EXT)]

    ubuf = ctypes.create_unicode_buffer(512)
    old_img_path = win32gui.SystemParametersInfo(win32con.SPI_GETDESKWALLPAPER, ubuf, 0)

    # 默认使用最新的一张图片
    idx = len(backgrounds) - 1

    # 上一张，或者下一张图片，必须在 相同目录下
    if step != 0 and old_img_path.startswith(SAVE_PATH):
        old_img_name = os.path.basename(old_img_path)
        idx = backgrounds.index(old_img_name)
        # 最后一张 还下一张,就去第一张
        if idx == len(backgrounds) - 1 and step > 0:
            idx = 0
        elif idx == 0 and step < 0:
            # 第一张 还上一张，就去最后一张
            idx = len(backgrounds) - 1
        else:
            idx = idx + step

    # 获取指定背景图片
    img_path = os.path.join(folder_path, backgrounds[idx])
    set_img_as_wallpaper(img_path)


# 初始加载所有的图片
def loadPics(num):
    # 文件夹不存在，创建文件夹
    if not os.path.exists(SAVE_PATH):
        print('图片保存提示：文件夹', SAVE_PATH, '不存在，已重新建立。', '\n')
        os.mkdir(SAVE_PATH)

    # 需要下载文件
    if num > 1:
        print('Bing每日一图将被保存在：', SAVE_PATH, '\n')
        imgs = judge_wait_retry_real_url(str(num))
        if len(imgs) > 0:
            save_bing_image(imgs, SAVE_PATH)
    elif num == 1:
        fileName = time.strftime("%Y%m%d", time.localtime()) + '.jpg'
        filePath = os.path.join(SAVE_PATH, fileName)
        if not os.path.exists(filePath):
            print('Bing每日一图将被保存在：', SAVE_PATH, '\n')
            imgs = judge_wait_retry_real_url(str(num))
            if len(imgs) > 0:
                save_bing_image(imgs, SAVE_PATH)


# 切换到今天的图片
def todayPic():
    # 加载今日图片
    loadPics(1)
    set_day_img_as_wallpaper(SAVE_PATH, 0)


# 上一张
def prevPic():
    set_day_img_as_wallpaper(SAVE_PATH, -1)


# 下一张
def nextPic():
    set_day_img_as_wallpaper(SAVE_PATH, 1)


# 解析获取真实图片路径
def get_rel_bing_img(json_url):
    with request.urlopen(json_url) as url:
        json_data = json.loads(url.read().decode())
    return json_data["images"]


# 网络不通进行等待
def judge_wait_retry_real_url(num):
    realImages = []
    for i in range(retryNum, allowTryNum):
        img_json_url = BASE_URL + num
        if test_network_live(img_json_url) and retryNum <= allowTryNum:
            realImages = get_rel_bing_img(img_json_url)
            break
        else:
            time.sleep(waitTime)
    return realImages


# 测试网络连通性
def test_network_live(testUrl):
    try:
        request.urlopen(testUrl)
        return True
    except:
        return False


# 添加右键菜单
def add_context_menu(node_name, menu_name, command, reg_root_key_path, reg_key_path, shortcut_key, icon_path,
                     sub_commands):
    '''
    封装的添加一个右键菜单的方法（含二级菜单）
    :param node_name: 注解表节点名称
    :param menu_name: 显示的菜单名称
    :param command: 菜单执行的命令
    :param reg_root_key_path: 注册表根键路径
    :param reg_key_path: 要添加到的注册表父键的路径（相对路径）
    :param shortcut_key: 菜单快捷键，如：'S'
    :param icon_path: icon
    :param sub_commands: 一级菜单的子菜单项，多个二级菜单用;隔开
    :return:
    '''
    # 打开名称父键
    key = reg.OpenKey(reg_root_key_path, reg_key_path)

    # 是否存在快捷键
    if len(shortcut_key) != 0:
        # 为key创建一个名称为menu_name的sub_key，并设置sub_key的值为menu_name加上快捷键，数据类型为REG_SZ字符串类型
        reg.SetValue(key, node_name, reg.REG_SZ, menu_name + '(&{0})'.format(shortcut_key))
    else:
        # 为key创建一个名称为menu_name的sub_key
        reg.SetValue(key, node_name, reg.REG_SZ, menu_name)

    # 打开刚刚创建的名为menu_name的sub_key
    sub_key = reg.OpenKey(key, node_name, 0, reg.KEY_ALL_ACCESS)
    # 传入了icon就设置icon
    if len(icon_path) != 0:
        reg.SetValueEx(sub_key, 'icon', 0, reg.REG_SZ, icon_path)
    if len(command) != 0:
        # 为sub_key添加名为'command'的子键，并设置其值为command + ' "%v"'，数据类型为REG_SZ字符串类型
        reg.SetValue(sub_key, 'command', reg.REG_SZ, command + ' "%v"')
    if len(sub_commands) != 0:
        reg.SetValueEx(sub_key, 'SubCommands', 0, reg.REG_SZ, sub_commands)

    # 关闭sub_key和key
    reg.CloseKey(sub_key)
    reg.CloseKey(key)


# 桌面右键快捷方式
def rightContextMenu():
    try:
        # 新增二级菜单 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell
        add_context_menu("BingImg.today",
                         '今天',
                         os.path.join(EXE_PATH, EXE_NAME) + ' today',
                         reg.HKEY_LOCAL_MACHINE,
                         r'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell',
                         '',
                         '',
                         '')
        # 新增二级菜单
        add_context_menu("BingImg.prev",
                         '上一张',
                         os.path.join(EXE_PATH, EXE_NAME) + ' prev',
                         reg.HKEY_LOCAL_MACHINE,
                         r'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell',
                         '',
                         '',
                         '')
        # 新增二级菜单
        add_context_menu("BingImg.next",
                         '下一张',
                         os.path.join(EXE_PATH, EXE_NAME) + ' next',
                         reg.HKEY_LOCAL_MACHINE,
                         r'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell',
                         '',
                         '',
                         '')

        # 新增一级菜单 计算机\HKEY_CLASSES_ROOT\Directory\Background\shell\BingImg
        add_context_menu("BingImg",
                         None,
                         '',
                         reg.HKEY_CLASSES_ROOT,
                         r'Directory\\Background\\shell',
                         '',
                         ICON_PATH,
                         "BingImg.today;BingImg.prev;BingImg.next;")
    except Exception as e:
        print('请以管理员身份运行！', '\n')


# 主函数
# 打包
# pyinstaller -i D:\python3_workspace\BingImg\logo.ico D:\python3_workspace\BingImg\BingImg.py --noconsole
if __name__ == '__main__':
    print(sys.argv)

    if len(sys.argv) > 1 :
        if sys.argv[1] == 'today':
            print('今天', '\n')
            todayPic()
        elif sys.argv[1] == 'prev':
            print('上一张', '\n')
            prevPic()
        elif sys.argv[1] == 'next':
            print('下一张', '\n')
            nextPic()
    else:
        print('新增注册表', '\n')
        rightContextMenu()
        print('加载8张图片', '\n')
        loadPics(8)